use std::any::Any;
use std::time::Duration;

use anyhow::Result;
use async_trait::async_trait;

use protoactor_rs::actor::{Actor, ActorContext, ActorError, DefaultActorContext, Props};
use protoactor_rs::system;

// 请求消息
#[derive(Debug)]
struct Add {
    a: i32,
    b: i32,
}

// 响应消息
#[derive(Debug, Clone)]
struct AddResult {
    result: i32,
}

// 计算器 Actor
struct CalculatorActor;

#[async_trait]
impl Actor for CalculatorActor {
    type Context = DefaultActorContext;
    
    async fn receive(&self, ctx: &mut Self::Context, msg: Box<dyn Any + Send>) -> Result<(), ActorError> {
        println!("CalculatorActor received message of type: {:?}", msg.type_id());
        
        // 处理 Add 消息
        if let Some(add) = msg.downcast_ref::<Add>() {
            println!("CalculatorActor received Add message: {:?}", add);
            
            // 计算结果
            let result = add.a + add.b;
            println!("Calculation result: {}", result);
            
            // 发送响应
            ctx.respond(AddResult { result });
            
            println!("Response sent");
        } else {
            println!("CalculatorActor received unknown message type");
        }
        
        Ok(())
    }
    
    async fn started(&self, _ctx: &mut Self::Context) -> Result<(), ActorError> {
        println!("CalculatorActor started");
        Ok(())
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    // 初始化全局 ActorSystem
    let system = system::get_or_create_system();
    println!("Global ActorSystem initialized");
    
    // 创建计算器 actor
    let props = Props::from_producer(|| CalculatorActor);
    let calculator_pid = system.spawn::<CalculatorActor>(props).await.unwrap();
    
    println!("CalculatorActor spawned with PID: {}", calculator_pid);
    
    // 发送请求并等待响应
    println!("Sending request: Add(2, 3)");
    let request = Add { a: 2, b: 3 };
    let timeout = Duration::from_secs(5);
    
    match calculator_pid.request::<AddResult>(request, timeout).await {
        Ok(result) => {
            println!("Received response: {:?}", result);
            println!("Calculation result: {}", result.result);
        },
        Err(e) => {
            println!("Request failed: {:?}", e);
        }
    }
    
    // 停止 actor
    system.stop(&calculator_pid).await?;
    
    println!("Test completed successfully");
    
    Ok(())
} 